ASM: LCD to PIC 4-bit writing to screen problem

Discussion in 'Embedded Systems and Microcontrollers' started by pic122, Jul 10, 2014.

  1. pic122

    Thread Starter New Member

    Jul 10, 2014
    8
    0
    Hi everyone,

    I have a problem with writing to a hitachi hd44780 16x2 display using the PIC16F1459. I have written several programs in C for this particular arrangement so I know from this that the wiring, LCD and PIC are all working correctly. I decided to switch over to writing in assembly because I wanted more control over the PIC. I am not a beginner with assembly would say I have a moderate understanding and have searched around a lot of forums and websites to better understand writing assembly for PIC's. However I cant seem to get the LCD to print out the correct characters. The code attached below initialises the LCD correctly - 16 boxes over 2 lines but when I want to write to it I can only get the LCD to print out 5 strange characters.

    Code ( (Unknown Language)):
    1.  
    2.  
    3. ; date: Tue 8th July                 *
    4. ; version: 1.0                       *
    5. ; filename: LCD                      *
    6. ; PIC: p16f1459                      *
    7. ; clock frequency: 4MHz              *
    8. ; cty: 1 us                          *
    9. ;*************************************
    10.  
    11. ;=================
    12. ; Config Settings
    13.  
    14.         list    P=16f1459
    15.         include "p16f1459.inc"
    16.  
    17. ; CONFIG1
    18. ; __config 0x3FE4
    19.  __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON
    20. ; CONFIG2
    21. ; __config 0x1FFF
    22.  __CONFIG _CONFIG2, _WRT_OFF & _CPUDIV_CLKDIV6 & _USBLSCLK_48MHz & _PLLMULT_3x & _PLLEN_ENABLED & _STVREN_ON & _BORV_LO & _LPBOR_OFF & _LVP_OFF
    23.  
    24.  
    25.  
    26.  
    27. ;======================
    28. ; Declarations
    29.  
    30. #define     LCD_PORT    LATC
    31. #define     LCD_RS      LATC,4
    32. #define     LCD_E       LATC,5
    33.  
    34. ; RW is grounded
    35. ; D4 ----> RC0
    36. ; D5 ----> RC1
    37. ; D6 ----> RC2
    38. ; D7 ----> RC3
    39.  
    40. ;=====================
    41. ; Variable Definitions
    42.  
    43.         cblock  H'20'
    44.         count
    45.         delay_1
    46.         delay_2
    47.         delay_3
    48.         tempLCD
    49.         endc
    50.  
    51. ;==============
    52. ; Reset Vector
    53.  
    54.         org   0x0000
    55.         goto  Start
    56.  
    57. Init
    58. ;====================
    59. ; Disable comparators
    60.  
    61.         bcf     CM1CON0,C1ON    ; clear C1ON
    62.         bcf     CM2CON0,C2ON    ; clear C2ON
    63.  
    64. ;========================
    65. ;Set Oscillator frequency
    66.  
    67.         banksel OSCCON
    68.         movlw   B'11110111'     ; 4MHz internal oscillator ; cty = 1us
    69.         movwf   OSCCON
    70.  
    71.         banksel TRISC           ; select LCD bus
    72.         movlw   B'00000000'     ; all pins output
    73.         movwf   TRISC
    74.  
    75.         banksel LATC
    76.         clrf    LATC
    77.        
    78.  
    79.         ; initialisation delay - 1 sec
    80.         movlw   D'100'
    81.         call    delay_long
    82.  
    83.         return
    84.  
    85. ;============================================
    86. ; Delay subroutine which lasts for 100 * cty
    87.  
    88. delay_long
    89.         movwf   delay_3
    90. delay_long_loop2
    91.         movlw   D'13'
    92.         movwf   delay_2
    93.         clrf    delay_1
    94. delay_long_loop1
    95.         decfsz  delay_1,f
    96.         goto    delay_long_loop1
    97.         decfsz  delay_2,f
    98.         goto    delay_long_loop1
    99.         decfsz  delay_3,f
    100.         goto    delay_long_loop2
    101.  
    102.         return
    103.  
    104. ;=========================
    105. ; Delay subroutine 10 * cty
    106.  
    107. delay_short
    108.         movwf   delay_2
    109. delay_short_loop2
    110.         movlw   D'249'
    111.         movwf   delay_1
    112. delay_short_loop1
    113.         nop
    114.         decfsz  delay_1,f
    115.         goto    delay_short_loop1
    116.         decfsz  delay_2,f
    117.         goto    delay_short_loop2
    118.  
    119.         return
    120.  
    121. ;==================
    122. ;LCD Initialisation
    123.  
    124. LCD_Init
    125.         banksel LATC
    126.         bcf     LCD_RS          ; commands so RS bit low
    127.  
    128.         movlw   D'16'
    129.         call    delay_short
    130.         banksel LATC
    131.         movlw   0x03
    132.         movwf   LCD_PORT
    133.         call    Nibble
    134.         movlw   D'6'
    135.         call    delay_short
    136.         banksel LATC
    137.         movlw   0x03
    138.         movwf   LCD_PORT
    139.         call    Nibble
    140.         movlw   D'1'
    141.         call    delay_short
    142.         banksel LATC
    143.         movlw   0x03
    144.         movwf   LCD_PORT
    145.         call    Nibble
    146.         movlw   D'5'
    147.         call    delay_short
    148.  
    149.         banksel LATC
    150.         movlw   0x20            ; set 4 bit mode
    151.         movwf   LCD_PORT
    152.         call    Nibble
    153.         movlw   0x28            ; 2 lines, 5 x 7 font
    154.         call    LCD_Cmd
    155.         movlw   0x08            ; display switch: D = 0, C = 0, B = 0
    156.         call    LCD_Cmd
    157.         movlw   0x0F            ; display switch: D = 1, C = 1, B = 1
    158.         call    LCD_Cmd
    159.         call    LCD_Clear       ; clear display
    160.         movlw   0x06            ; input set: I/D = 1, S = 0
    161.         call    LCD_Cmd
    162.  
    163.  
    164.         return
    165.  
    166. ;============
    167. ; Send nibble
    168.  
    169. Nibble
    170.         banksel LATC
    171.         bsf     LCD_E           ; high
    172.         movlw   D'1'
    173.         call    delay_short
    174.         banksel LATC
    175.         bcf     LCD_E           ; low
    176.         movlw   D'2'
    177.         call    delay_short
    178.  
    179.         return
    180.  
    181. ;============
    182. ; LCD Command
    183.  
    184. LCD_Cmd
    185.         movwf   tempLCD
    186.         swapf   tempLCD         ; higher nibble to W
    187.         movfw   tempLCD
    188.         andlw   0xF0
    189.         banksel LATC
    190.         bcf     LCD_RS          ; RS set low due to instruction write
    191.         banksel LATC
    192.         movwf   LCD_PORT
    193.         call    Nibble
    194.         movlw   D'2'
    195.         call    delay_short
    196.  
    197.         swapf   tempLCD         ; lower nibble to W
    198.         movfw   tempLCD
    199.         andlw   0xF0
    200.         banksel  LATC
    201.         bcf     LCD_RS
    202.         banksel LATC
    203.         movwf   LCD_PORT
    204.         banksel  LATC
    205.         bcf     LCD_RS
    206.         call    Nibble
    207.         movlw   D'10'
    208.         call    delay_short
    209.  
    210.         return
    211.  
    212. ;==========
    213. ; LCD Write
    214.  
    215. LCD_Write
    216.         movwf   tempLCD
    217.         swapf   tempLCD         ; higher nibble to W
    218.         movfw   tempLCD
    219.         andlw   0xF0
    220.         banksel LATC
    221.         bsf     LCD_RS          ; RS set high due to data write
    222.         banksel LATC
    223.         movwf  LCD_PORT
    224.         call   Nibble
    225.         movlw   D'2'
    226.         call    delay_short
    227.  
    228.         swapf   tempLCD         ; lower nibble to W
    229.         movfw   tempLCD
    230.         andlw   0xF0
    231.         banksel LATC
    232.         bsf     LCD_RS
    233.         banksel LATC
    234.         movwf   LCD_PORT
    235.         call    Nibble
    236.         movlw   D'10'
    237.         call    delay_short
    238.  
    239.         return
    240.  
    241. ;===========
    242. ; LCD line 1
    243.  
    244. LCD_Line1
    245.         movlw   0x80
    246.         call    LCD_Cmd
    247.  
    248.         return
    249.  
    250. ;===========
    251. ; LCD line 2
    252.  
    253. LCD_Line2
    254.         movlw   0xC0
    255.         call    LCD_Cmd
    256.  
    257.         return
    258.  
    259. ;==============
    260. ; Clear Command
    261.  
    262. LCD_Clear
    263.         movwf   0x01
    264.         call    LCD_Cmd
    265.  
    266.         return
    267.  
    268. ;=============
    269. ; Program main
    270. Start
    271.         call    Init
    272.         call    LCD_Init
    273.  
    274. Main
    275.         movlw   0x50        ;P
    276.         call    LCD_Write
    277.         movlw   0x49        ;I
    278.         call    LCD_Write
    279.         movlw   0x43        ;C
    280.         call    LCD_Write
    281.         goto    $           ; loop forever
    282.  
    283.         end
    284.  
    285.  
    286.  

    I have a few ideas what might be wrong the obvious one is the LCD_Write subroutine also I'm wondering whether the PIC is correctly initialised. I would be grateful if you could look over the code.

    Thanks.


     
  2. takao21203

    Distinguished Member

    Apr 28, 2012
    3,577
    463
    using assembler, there are countless things that can go wrong.

    Did you run the program in a simulator?
    Did you try to reduce the clocking frequency?
    Is the LCD OK?

    Go through the datasheet again, and check your code step by step.
    Remove everything that is not required.

    b) dont use ASM it does not give you more control.
     
    pic122 likes this.
  3. MaxHeadRoom

    Expert

    Jul 18, 2013
    10,548
    2,373
    pic122 likes this.
  4. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    Hi pic122. Welcome to the Forum.

    I didn't see where you turned off the analog functions for PORTC in your code.

    Are you sure you've got correct Config' and OSCCON settings for 4-MHz INTOSC?

    Looks like you're masking off the wrong nibble in your LCD_Cmd and LCD_Write subroutines. That will definitely mess up the HD44780 LCD "initialization by instruction" procedure.

    This section in LCD_Init is incorrect (operand should be 0x02 instead of 0x20);

    Code ( (Unknown Language)):
    1.         banksel LATC
    2.         movlw   0x20            ; set 4 bit mode
    3.         movwf   LCD_PORT
    4.  
    Also, the LCD 'home' and 'clear' commands usually require a ~1550 us delay to complete.

    Perhaps you can try to flash an LED at some interval to verify correct config, ANSELC, and OSCCON settings?

    Good luck on your project.

    Cheerful regards, Mike
     
    Last edited: Jul 11, 2014
  5. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    Nigel Goodwin has some good ASM tutorials for using a Hitchi 44780 text LCD in PIC assembler. He's an old timer that knows his stuff, so his code and examples will be properly tested and have been used by many people;

    http://www.winpicprog.co.uk/pic_tutorial3.htm
    :)
     
    pic122 likes this.
  6. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,389
    1,605
    First off, welcome to the forums.

    Next, please note 4 very experienced people read your post and none of them read your code. They may have wandered thru it briefly but no one will give it the detailed study you can.

    Do you have a PICkit for programming? If you do, it can also work as an in circuit debugger, though you need to keep it's connection pins free. I always keep those pins available in every project so I can do such debugging. With just a DVM (or even a LED) you can check all the pins for proper ones and zeros.

    Sometimes your code only works when single stepping. That's good news as it means your delays are the problem. (Always make the delays hugely large in the beginning; once you can see "Hello World" on the display you can start slimming things down to quick but still works 100%)

    If not, there is always the simulator. You can step thru your code line by line (and it's oft OK to comment out long delays) to see if the correct pins wiggle when commanded.

    Good luck!
     
    pic122 likes this.
  7. MaxHeadRoom

    Expert

    Jul 18, 2013
    10,548
    2,373
    Signal Generator/Logic Analyzer = Pickit2 but not Pickit3, unfortunately.;)
    Max.
     
  8. MaxHeadRoom

    Expert

    Jul 18, 2013
    10,548
    2,373
  9. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,389
    1,605
    I did not say "Signal Generator/Logic Analyzer."

    I did say "in circuit debugger" which is a function of both PICkit 2 and 3.
     
  10. MaxHeadRoom

    Expert

    Jul 18, 2013
    10,548
    2,373
    Are you saying that The Pickit will perform the ICD2/ICD3 functions?
    If so I must have missed this?
    OK I see it mentions this, I stand corrected.
    Max.
     
  11. pic122

    Thread Starter New Member

    Jul 10, 2014
    8
    0
    Hi all.

    Wow thank you for all your replies. I will take my time to go through them all and try out your suggestions and will post back my progress.

    Thanks once again.
     
  12. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    pic122,

    Just spotted some more code problems; (1) over-writing the RS bit in your LCD_Write routine and incorrect bank selection.

    Let me put some notes together for you, Sir.

    Regards, Mike
     
    pic122 likes this.
  13. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,389
    1,605
    Well gee, you're not the only one not to realize that the PICkit 2 Development Programmer/Debugger is both a programmer AND a debugger.

    I imagine the confusion that name must have caused, which may be why Microchip names the next version the PICkit 3 In-Circuit Debugger so someone just might notice it also works as a debugger.

    I'm just waiting for the day for someone to ask "I only have a PICkit 3 debugger. What do I need to do programming?"

    :D
     
  14. pic122

    Thread Starter New Member

    Jul 10, 2014
    8
    0
    Hi everyone.

    Thank you for all your suggestions, links and help I have had success and now have a fully functioning LCD display using assembly code!

    The problem was with the LCD_Cmd and LCD_Write routines I didn't fully understand the difference between moving the contents into a temporary file register and using the w register to perform instructions. So throughout my two routines I was overwriting the nibbles with the values I was using for the delay routine hence the garbage on the LCD. Also as MMcLaren pointed out I was overwriting the RS bit when trying to use the LCD_Write routine.

    I solved this by using the simulator in mplab x as suggested and step through the code line by line whilst looking at Window > PIC Memory Views > SFRs where I could see the affect of each instruction on the various ports on the PIC.

    Also I set the pins to digital and changed the 4 bit command to 0x02 from the wrong value.

    Here is the working code below:

    Code ( (Unknown Language)):
    1.  
    2.  
    3. ;=================
    4. ; Config Settings
    5.  
    6.         list    P=16f1459
    7.         include "p16f1459.inc"
    8.  
    9. ; CONFIG1
    10. ; __config 0x3FE4
    11.  __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON
    12. ; CONFIG2
    13. ; __config 0x1FFF
    14.  __CONFIG _CONFIG2, _WRT_OFF & _CPUDIV_CLKDIV6 & _USBLSCLK_48MHz & _PLLMULT_3x & _PLLEN_ENABLED & _STVREN_ON & _BORV_LO & _LPBOR_OFF & _LVP_OFF
    15.  
    16.  
    17.  
    18.  
    19. ;======================
    20. ; Declarations
    21.  
    22. #define     LCD_PORT    LATC
    23. #define     LCD_RS      LATC,4
    24. #define     LCD_E       LATC,5
    25.  
    26.  
    27. ; RW is grounded
    28. ; D4 ----> RC0
    29. ; D5 ----> RC1
    30. ; D6 ----> RC2
    31. ; D7 ----> RC3
    32.  
    33. ;=====================
    34. ; Variable Definitions
    35.  
    36.         cblock  H'20'
    37.         delay_1
    38.         delay_2
    39.         delay_3
    40.         tempLCD
    41.         endc
    42.  
    43. ;==============
    44. ; Reset Vector
    45.  
    46.         org   0x0000
    47.         goto  Start
    48.  
    49. Init
    50. ;====================
    51. ; Disable comparators
    52.  
    53.         bcf     CM1CON0,C1ON    ; clear C1ON
    54.         bcf     CM2CON0,C2ON    ; clear C2ON
    55.  
    56. ;========================
    57. ;Set Oscillator frequency
    58.  
    59.         banksel OSCCON
    60.         movlw   B'00110111'     ; 4MHz internal oscillator ; cty = 1us
    61.         movwf   OSCCON
    62.  
    63. ;=====================
    64. ; Set up port and pins
    65.  
    66.         banksel TRISC           ; select TRISC bus
    67.         movlw   B'00000000'     ; all pins output
    68.         movwf   TRISC
    69.  
    70.         banksel LATC            ; select LATC and clear
    71.         clrf    LATC
    72.  
    73.         banksel ANSELC          ; set all pins to digital
    74.         clrf    ANSELC
    75.  
    76.         return
    77.  
    78. ;============================================
    79. ; Delay subroutine which lasts for 100 * cty
    80.  
    81. delay_long
    82.         movwf   delay_3
    83. delay_long_loop2
    84.         movlw   D'13'
    85.         movwf   delay_2
    86.         clrf    delay_1
    87. delay_long_loop1
    88.         decfsz  delay_1,f
    89.         goto    delay_long_loop1
    90.         decfsz  delay_2,f
    91.         goto    delay_long_loop1
    92.         decfsz  delay_3,f
    93.         goto    delay_long_loop2
    94.  
    95.         return
    96.  
    97. ;============================
    98. ; Delay subroutine 1000 * cty
    99.  
    100. delay_short
    101.         movwf   delay_2
    102. delay_short_loop2
    103.         movlw   D'249'
    104.         movwf   delay_1
    105. delay_short_loop1
    106.         nop
    107.         decfsz  delay_1,f
    108.         goto    delay_short_loop1
    109.         decfsz  delay_2,f
    110.         goto    delay_short_loop2
    111.  
    112.         return
    113.  
    114. ;==================
    115. ;LCD Initialisation
    116.  
    117. LCD_Init
    118.         movlw   D'5'
    119.         call    delay_long
    120.  
    121.         banksel LATC
    122.         bcf     LCD_RS          ; commands so RS bit set low
    123.         movlw   D'16'           ; must be more than 15ms
    124.         call    delay_short
    125.         banksel LATC
    126.         movlw   0x03            ; send first high nibble
    127.         movwf   LCD_PORT
    128.         call    Nibble
    129.         movlw   D'6'            ; must be more than 4.1ms
    130.         call    delay_short
    131.         banksel LATC
    132.         movlw   0x03            ; send second high nibble
    133.         movwf   LCD_PORT
    134.         call    Nibble
    135.         movlw   D'1'            ; must be more than 100us
    136.         call    delay_short
    137.         banksel LATC
    138.         movlw   0x03            ; send third high nibble
    139.         movwf   LCD_PORT
    140.         call    Nibble
    141.         movlw   D'5'            ; must be more than 5ms
    142.         call    delay_short
    143.  
    144.         banksel LATC
    145.         movlw   0x02            ; set 4 bit mode
    146.         movwf   LCD_PORT
    147.         call    Nibble
    148.         movlw   0x28            ; function set: 4 bit, 2 lines, 5 x 7 font
    149.         call    LCD_Cmd
    150.         movlw   0x08            ; display switch: D = 0, C = 0, B = 0
    151.         call    LCD_Cmd
    152.         call    LCD_Clear
    153.         movlw   0x0C            ; display switch: D = 1, C = 0, B = 0
    154.         call    LCD_Cmd
    155.  
    156.         movlw   0x06            ; input set: I/D = 1, S = 0
    157.         call    LCD_Cmd
    158.  
    159.         banksel LATC            ; make sure LATC port is clear
    160.         clrf    LATC
    161.  
    162.         movlw   D'50'           ; initialisation delay
    163.         call    delay_long
    164.  
    165.         return
    166.  
    167. ;============
    168. ; LCD Command
    169.  
    170. ;****************************
    171. ;                           *
    172. ; RS   ___________________  *
    173. ;                           *
    174. ; R/W  ___________________  *
    175. ;              __           *
    176. ; E    _______/  \________  *
    177. ;         _____________     *
    178. ; D4/7 __/   Command   \__  *
    179. ;                           *
    180. ;****************************
    181.  
    182. LCD_Cmd
    183.         movwf   tempLCD           ; move contents of w into tempLCD
    184.         swapf   tempLCD,w         ; swap contents of tempLCD put result in w
    185.         andlw   0xf               ; select high nibble
    186.         banksel LATC
    187.         movwf   LCD_PORT
    188.         banksel LATC
    189.         bcf     LCD_RS            ; RS set low due to instruction write
    190.         call    Nibble
    191.         movlw   D'1'
    192.         call    delay_short
    193.  
    194.         movfw   tempLCD           ; move contents of tempLCD into w
    195.         andlw   0xf               ; select low nibble
    196.         banksel LATC
    197.         movwf   LCD_PORT
    198.         banksel LATC
    199.         bcf     LCD_RS            ; RS set low due to instruction write
    200.         call    Nibble
    201.         movlw   D'1'
    202.         call    delay_short
    203.  
    204.         return
    205.  
    206. ;==========
    207. ; LCD Write
    208.  
    209. ;****************************
    210. ;         ________________  *
    211. ; RS   __/                  *
    212. ;                           *
    213. ; R/W  ___________________  *
    214. ;              __           *
    215. ; E    _______/  \________  *
    216. ;         _____________     *
    217. ; D4/7 __/    Data     \__  *
    218. ;                           *
    219. ;****************************
    220.  
    221. LCD_Write
    222.         movwf   tempLCD           ; move contents of w into tempLCD
    223.         swapf   tempLCD,w         ; swap contents of tempLCD put result in w
    224.         andlw   0xf               ; select high nibble
    225.         banksel LATC
    226.         movwf   LCD_PORT
    227.         banksel LATC
    228.         bsf     LCD_RS            ; RS set high due to instruction write
    229.         call    Nibble
    230.         movlw   D'1'
    231.         call    delay_short
    232.  
    233.         movfw   tempLCD           ; move contents of tempLCD into w
    234.         andlw   0xf               ; select low nibble
    235.         banksel LATC
    236.         movwf   LCD_PORT
    237.         banksel LATC
    238.         bsf     LCD_RS            ; RS set high due to instruction write
    239.         call    Nibble
    240.         movlw   D'5'              ; vary this delay to control writing speed
    241.         call    delay_long
    242.         return
    243.  
    244. ;===========================
    245. ; Send nibble - toggle E pin
    246.  
    247. Nibble
    248.         banksel LATC
    249.         bsf     LCD_E             ; E set high
    250.         movlw   D'1'
    251.         call    delay_short
    252.         banksel LATC
    253.         bcf     LCD_E             ; E set low
    254.         movlw   D'2'
    255.         call    delay_short
    256.  
    257.         return
    258.  
    259. ;===========
    260. ; LCD line 1
    261.  
    262. LCD_Line1
    263.         movlw   0x80
    264.         call    LCD_Cmd
    265.  
    266.         return
    267.  
    268. ;===========
    269. ; LCD line 2
    270.  
    271. LCD_Line2
    272.         movlw   0xC0
    273.         call    LCD_Cmd
    274.  
    275.         return
    276.  
    277. ;==============
    278. ; Clear Command
    279.  
    280. LCD_Clear
    281.         movlw   0x01
    282.         call    LCD_Cmd
    283.  
    284.         return
    285.  
    286. ;============
    287. ; Write Space
    288.  
    289. LCD_Space
    290.         movlw   0x20
    291.         call    LCD_Write
    292.  
    293.         return
    294.  
    295. ;=============
    296. ; Program main
    297.  
    298. Start
    299.         call    Init
    300.         call    LCD_Init
    301.  
    302. Main
    303.         call    LCD_Clear
    304.         call    LCD_Line1
    305.  
    306. Top_Line
    307.         movlw   'H'
    308.         call    LCD_Write
    309.         movlw   'e'
    310.         call    LCD_Write
    311.         movlw   'l'
    312.         call    LCD_Write
    313.         movlw   'l'
    314.         call    LCD_Write
    315.         movlw   'o'
    316.         call    LCD_Write
    317.         call    LCD_Space
    318.         movlw   'W'
    319.         call    LCD_Write
    320.         movlw   'o'
    321.         call    LCD_Write
    322.         movlw   'r'
    323.         call    LCD_Write
    324.         movlw   'l'
    325.         call    LCD_Write
    326.         movlw   'd'
    327.         call    LCD_Write
    328.         movlw   D'255'
    329.         call    delay_long
    330.  
    331. Bottom_Line
    332.         call    LCD_Line2
    333.         movlw   'I'
    334.         call    LCD_Write
    335.         movlw   't'
    336.         call    LCD_Write
    337.         movlw   0X27
    338.         call    LCD_Write
    339.         movlw   's'
    340.         call    LCD_Write
    341.         call    LCD_Space
    342.         movlw   'p'
    343.         call    LCD_Write
    344.         movlw   'i'
    345.         call    LCD_Write
    346.         movlw   'c'
    347.         call    LCD_Write
    348.         movlw   '1'
    349.         call    LCD_Write
    350.         movlw   '2'
    351.         call    LCD_Write
    352.         movlw   '2'
    353.         call    LCD_Write
    354.         movlw   D'255'
    355.         call    delay_long
    356.  
    357.         goto    $                  ; loop forever
    358.  
    359.         end
    360.  
    361.  
    I also followed MacHeadRoom's suggestion and have successfully written another bit of code which uses the busy flag rather than delays.

    Also going to incorporate a lookup table and to answer a question I'm using a PICKit 3.

    Regards,
    pic122.
     
  15. MaxHeadRoom

    Expert

    Jul 18, 2013
    10,548
    2,373
    Back when I picked mine up they were pushing the ICD-2 and then the 3, for both programming and In Cir debugging.
    Now the Pikit3 is virtually identical in function to the ICD-2.
    Max.
     
  16. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    Congrats', pic122. Happy to hear you're using the Simulator. When you get time, please check out your banking and you'll find you're using variable locations in bank 2 instead of bank 0. While it works ok for you in this case, it may become a problem in the future.

    Your code looks great but your timing is off. While your code works fine, please check out the timing in the Hitachi HD44780 Datasheet for the "initialization by instruction" procedure for 4-bit interface mode. A simple fixed delay subsystem should handle most of your timing requirements.

    Plenty of opportunities for optimizing your code, for example;

    Code ( (Unknown Language)):
    1. Nibble_cmd
    2.         clrc                    ; RS = 0 (command)                |00
    3. Nibble_alt
    4.         banksel LCD_PORT        ; bank 2                          |02
    5.         andlw   0x0F            ;                                 |02
    6.         skpnc                   ; C = 0? yes, skip (RS=0), else   |02
    7.         iorlw   b'00010000'     ; set RS bit (RC4)                |02
    8.         movwf   LCD_PORT        ;                                 |02
    9.         bsf     LCD_E           ; toggle lcd 'E' pin              |02
    10.         nop                     ;                                 |02
    11.         nop                     ;                                 |02
    12.         bcf     LCD_E           ;                                 |02
    13.         movlb   0               ; bank 0                          |00
    14.         return                  ;                                 |00
    15.  
    Code ( (Unknown Language)):
    1.  
    2. LCD_Data
    3.         setc                    ; C = 1 (data)                    |00
    4.         skpc                    ; skip unconditionally            |00
    5.  
    6. LCD_Cmd_alt
    7.         clrc                    ; C = 0 (command)                 |00
    8.         movwf   tempLCD         ;                                 |00
    9.         swapf   tempLCD,W       ; hi nibble in b3..b0 bits        |00
    10.         call    Nibble_alt      ; write hi nibble to LCD          |00
    11.         movf    tempLCD,W       ; lo nibble in b3..b0 bits        |00
    12.         call    Nibble_alt      ; write lo nibble to LCD          |00
    13.         delayCy(50*usecs)       ; 50-us inter-write delay         |00
    14.         return                  ;                                 |00
    15.  
    Code ( (Unknown Language)):
    1. ;
    2. ;  HD44780 "initialization by instruction" procedure for 4-bit mode
    3. ;
    4. LCD_Init
    5.         movlb   0               ; bank 0                          |00
    6.         delayCy(50*msecs)       ; LCD 50 msec 'power up' reset    |00
    7.         movlw   0x03            ; hi nibble of 0x30 '8-bit' cmd   |00
    8.         call    Nibble_cmd      ; step 1                          |00
    9.         delayCy(4*msecs)        ; required delay                  |00
    10.         movlw   0x03            ; hi nibble of 0x30 '8-bit' cmd   |00
    11.         call    Nibble_cmd      ; step 2                          |00
    12.         delayCy(160*usecs)      ; required delay                  |00
    13.         movlw   0x03            ; hi nibble of 0x30 '8-bit' cmd   |00
    14.         call    Nibble_cmd      ; step 3                          |00
    15.         delayCy(160*usecs)      ; required delay                  |00
    16.         movlw   0x02            ; hi nibble of 0x20 '4-bit' cmd   |00
    17.         call    Nibble_cmd      ; step 4                          |00
    18.         delayCy(160*usecs)      ; required delay                  |00
    19. ;
    20. ;  now in 4-bit interface mode. ok to send full bytes.
    21. ;
    22.         movlw   0x28            ; 4-bit, 2-lines, 5x7 font        |00
    23.         call    LCD_Cmd_alt     ; send "function set" command     |00
    24.         movlw   0x0C            ; display on, cursor & blink off  |00
    25.         call    LCD_Cmd_alt     ; send "display on/off" command   |00
    26.         movlw   0x06            ; cursor inc, shift off           |00
    27.         call    LCD_Cmd_alt     ; send "entry mode set" command   |00
    28.         movlw   0x01            ; clear display (1.53-msecs)      |00
    29.         call    LCD_Cmd_alt     ; send "entry mode set" command   |00
    30.         delayCy(1530*usecs)     ; 1.53 msec delay for "clear"     |00
    31.         return                  ;                                 |00
    32.  
    The "enhanced mid-range" devices provide access to the stack which could be exploited to build a PutStr routine with in-line string storage;

    Code ( (Unknown Language)):
    1. ;
    2. ; PutStr macro usage example
    3. ;
    4.         call    LCD_Line1       ;                                 |00
    5.         PutStr "Hello World"    ;                                 |00
    6.         call    LCD_Line2       ;                                 |00
    7.         PutStr "It's pic122"    ;                                 |00
    8.  
    9.  
    Code ( (Unknown Language)):
    1. PutStr  macro   string
    2.         call    PutStrg         ; print in-line string
    3.         dt      string,0        ; null terminated in-line string
    4.         endm
    5.  
    Code ( (Unknown Language)):
    1. ;
    2. ;  PutStrg subroutine - pull in-line string address from top of
    3. ;  stack, print string up to the null terminator, then return
    4. ;  to the address immediately following the in-line string.
    5. ;
    6. PutStrg
    7.     banksel TOSL        ; bank 31             |31
    8.     movf    TOSL,W      ; top of stack lo         |31
    9.     movwf   FSR1L       ;                 |31
    10.     movf    TOSH,W      ; top of stack hi         |31
    11.     iorlw   0x80            ; set FSR1 b15 for rom access     |31
    12.     movwf   FSR1H       ;                 |31
    13. getchar
    14.         banksel TOSL            ; bank 31                         |31
    15.     moviw   INDF1++     ; null terminator?        |31
    16.     bz  putexit     ; yes, exit, else         |31
    17.     call    LCD_Data        ; send char to LCD        |00
    18.     bra getchar     ; loop                |00
    19. putexit
    20.         movf    FSR1L,W         ; adjust return address           |31
    21.         movwf   TOSL            ;                                 |31
    22.         movf    FSR1H,W         ;                                 |31
    23.         andlw   0x7F            ;                                 |31
    24.         movwf   TOSH            ;                                 |31
    25.         movlb   0               ; bank 0                          |00
    26.         return                  ;                                 |00
    27.  
    Food for thought (forgive me for butting in).

    Cheerful regards, Mike
     
    Last edited: Jul 12, 2014
    absf likes this.
  17. pic122

    Thread Starter New Member

    Jul 10, 2014
    8
    0
    Thank you for all your ideas to optimise my code and the examples you have given. I will go through and have a good look at everything.
     
  18. pic122

    Thread Starter New Member

    Jul 10, 2014
    8
    0
    Do you mean by this that cblock which has a value of H'20' in my code should be something different?
     
    Last edited: Jul 13, 2014
  19. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    I mean that you're forgetting to use banksel statements before accessing those variables so you're actually in bank 2. That means you're accessing RAM locations at 0x120..0x124 instead of 0x020..0x024.

    Since your code is always in bank 2 when you access those few variables, you could probably define them in bank 2 locations starting at 0x120. However many programmers will just make sure to switch back to bank 0 by default at the end of any routine that does bank switching.
     
  20. pic122

    Thread Starter New Member

    Jul 10, 2014
    8
    0
    So what you want to be doing is working in bank 0 with the variables and switching when you need to go to other banks and then switch back to bank 0 again.

    For example in my code the Init routine should end ike this
    Code ( (Unknown Language)):
    1.  
    2. movlb   0
    3. return
    Is my understand of this now correct? I am now going to incorporate your optimising code suggestions which by looking at I can see you are able to avoid switching banks too often by carefully choosing which routine uses which bank.

    Thank you for the help I have learnt a lot in these last few days.

    Regards,

    pic122
     
Loading...